<template>
  <div>
    <div style="width:600px;height:100px">{{sourceData}}</div>
    <label>
      默认选中 :
      <input type="text" name="skuId" id="skuId" v-model="skuId">
    </label>
    <button @click="getTextareaData" class="top-but"> 重新加载数据 </button> 当前属性ID：{{ skuId }}
    <dl v-for="(item, key) in list.result" :key="key" class="content" :class="{hl: highKeys[key]}">
      <dt> {{key}} : </dt>
      <dd>
        <button class="item" v-for="(value,indexSon) in item" :key="indexSon" @click="handleActive(key, value)" :class="{active: value.active, disabled: !value.active && value.disabled}"> {{ value.name }} </button>
      </dd>
    </dl>
    已经选择：{{ message }}
  </div>
</template>

<script>
export default {
    name: 'HelloWorld',
    props: {
        msg: String
    },
    data() {
        return {
            sourceData: [
                { "颜色": "红", "尺码": "大", "型号": "A", "skuId": "3158055" },
                { "颜色": "白", "尺码": "大", "型号": "A", "skuId": "3158054" },
                { "颜色": "白", "尺码": "中", "型号": "B", "skuId": "3133859" },
                { "颜色": "蓝", "尺码": "小", "型号": "C", "skuId": "3516833" }
            ],
            data: [],
            skuId: "3158055", //默认选中的sku的值
            skuName: "skuId", //sku的id的键名
            keys: [],  // 属性名称信息,如:["颜色","尺码","型号"]
            list: {},  // 数据集合{list.result list.items}
            spliter: '\u2299', //分隔符⊙
            result: {}, //取得集合的所有子集
            message: "", //选中的sku的数据
            highKeys: {}, //高亮的行
        }
    },
    created() {
        this.getTextareaData();
    },
    methods: {
        powerset(arr) {
            let ps = [[]];
            for (let i = 0; i < arr.length; i++) {
                for (let j = 0, len = ps.length; j < len; j++) {
                    ps.push(ps[j].concat(arr[i]));
                }
            }
            return ps;
        },

        /**
         * 初始化数据
         * @return 
         */
        initData() {
            this.result = {};
            this.keys = this.getAllKeys();
            for (let i = 0; i < this.keys.length; i++) {
                this.highKeys[this.keys[i]] = false;
            }

            this.list = this.combineAttr(this.data, this.keys);
            this.initSeleted(this.skuId);
            this.buildResult(this.list.items)
            this.updateStatus(this.getSelectedItem());
            this.showResult();
        },

        /**
         * 获取输入表单中的数据进行初始化
         * @return
         */
        getTextareaData() {
            let skuId = this.skuId;
            try {
                this.data = this.sourceData;
                let isHas = false;
                for (let i = 0; i < this.data.length; i++) {
                    if (skuId == this.data[i][this.skuName]) {
                        isHas = true;
                        break
                    }
                }

                this.skuId = isHas ? skuId : this.data[0][this.skuName];
                this.initData();
            } catch (e) {
                this.data = [];
            }
        },

        /**
         * 正常属性点击
         */
        handleNormalClick(key, value) {
            for (let i in this.list.result[key]) {
                if (i != value.name) {
                    this.list.result[key][i].active = false;
                } else {
                    this.list.result[key][i].active = true;
                }
            }
        },

        /**
         * 无效属性点击
         */
        handleDisableClick(key, value) {
            this.list.result[key][value.name]["disabled"] = false;
            // 清空高亮行的已选属性状态（因为更新的时候默认会跳过已选状态）
            for (let i in this.list.result) {
                if (i != key) {
                    for (let x in this.list.result[i]) {
                        this.list.result[i][x].active = false;
                    }
                }
            }

            this.updateStatus(this.getSelectedItem());
        },

        /**
         * 高亮行
         */
        highAttributes: function () {
            for (let key in this.list.result) {
                this.highKeys[key] = true;
                for (let attr in this.list.result[key]) {
                    if (this.list.result[key][attr].active === true) {
                        this.highKeys[key] = false;
                        break;
                    }
                }
            }
        },

        /**
         * 点击事件处理
         * @param  key   点击的行
         * @param  value 点击的按钮的数据
         */
        handleActive: function (key, value) {
            if (value.active == true) {
                return false;
            }

            this.handleNormalClick(key, value);
            if (value.disabled === true) {
                this.handleDisableClick(key, value);
            }

            this.updateStatus(this.getSelectedItem());
            this.highAttributes();
            this.showResult();
        },

        /**
         * 计算属性
         * @param  {[type]} data [description]
         * @param  {[type]} keys [description]
         * @return {[type]}      [description]
         */
        combineAttr(data, keys) {
            let allKeys = []
            let result = {}
            for (let i = 0; i < data.length; i++) {
                let item = data[i]
                let values = []
                for (let j = 0; j < keys.length; j++) {
                    let key = keys[j]
                    if (!result[key]) {
                        result[key] = {};
                    }
                    if (!result[key][item[key]]) {
                        result[key][item[key]] = { "name": item[key], "active": false, "disabled": true };
                    }
                    values.push(item[key]);
                }
                allKeys.push({
                    path: values.join(this.spliter),
                    sku: item['skuId']
                });
            }
            return {
                result: result,
                items: allKeys
            }
        },

        /**
         * 获取所有属性
         * @return {[type]} [description]
         */
        getAllKeys() {
            let arrKeys = [];
            for (let attribute in this.data[0]) {
                if (!Object.hasOwnProperty.call(this.data[0], attribute)) {
                    continue;
                }

                if (attribute !== this.skuName) {
                    arrKeys.push(attribute);
                }
            }

            return arrKeys;
        },

        getAttruites(arr) {
            let result = []
            for (let i = 0; i < arr.length; i++) {
                result.push(arr[i].path)
            }

            return result
        },

        /**
         * 生成所有子集是否可选、库存状态 map
         */
        buildResult(items) {
            let allKeys = this.getAttruites(items)

            for (let i = 0; i < allKeys.length; i++) {
                let curr = allKeys[i];
                let sku = items[i].sku;
                let values = curr.split(this.spliter);
                let allSets = this.powerset(values);

                // 每个组合的子集
                for (let j = 0; j < allSets.length; j++) {
                    let set = allSets[j]
                    let key = set.join(this.spliter)

                    if (this.result[key]) {
                        this.result[key].skus.push(sku)
                    } else {
                        this.result[key] = {
                            skus: [sku]
                        }
                    }
                }
            }
        },

        /**
         * 获取选中的信息
         * @return Array 
         */
        getSelectedItem() {
            let result = [];
            for (let attr in this.list.result) {
                let attributeName = '';
                for (let attribute in this.list.result[attr]) {
                    if (this.list.result[attr][attribute].active === true) {
                        attributeName = attribute;
                    }
                }

                result.push(attributeName);
            }

            return result
        },

        /**
         * 更新所有属性状态
         */
        updateStatus(selected) {
            for (let i = 0; i < this.keys.length; i++) {
                let key = this.keys[i],
                    data = this.list.result[key],
                    // hasActive = !!selected[i],
                    copy = selected.slice();

                for (let j in data) {
                    let item = data[j]["name"];
                    if (selected[i] == item) {
                        continue
                    }

                    copy[i] = item
                    let curr = this.trimSpliter(copy.join(this.spliter), this.spliter);
                    this.list.result[key][j]["disabled"] = this.result[curr] ? false : true;
                }
            }
        },

        trimSpliter(str, spliter) {
            // ⊙abc⊙ => abc
            // ⊙a⊙⊙b⊙c⊙ => a⊙b⊙c
            let reLeft = new RegExp('^' + spliter + '+', 'g');
            let reRight = new RegExp(spliter + '+$', 'g');
            let reSpliter = new RegExp(spliter + '+', 'g');
            return str.replace(reLeft, '')
                .replace(reRight, '')
                .replace(reSpliter, spliter)
        },

        /**
         * 初始化选中
         * @param  mixed|Int|String skuId 需要选中的skuId
         * @return {[type]}       [description]
         */
        initSeleted(skuId) {
            for (let i in this.data) {
                if (this.data[i][this.skuName] == skuId) {
                    for (let x in this.data[i]) {
                        if (x !== this.skuName) {
                            this.list.result[x][this.data[i][x]].active = true;
                        }
                    }
                    break;
                }
            }
        },

        /**
         * 显示选中的信息
         * @return 
         */
        showResult() {
            let result = this.getSelectedItem()
            let s = []
            for (let i = 0; i < result.length; i++) {
                let item = result[i];
                if (item) {
                    s.push(item)
                }
            }
            if (s.length == this.keys.length) {
                let curr = this.result[s.join(this.spliter)]
                if (curr) {
                    s = s.concat(curr.skus)
                    this.skuId = curr.skus[0];
                }

                this.message = s.join('\u3000-\u3000');
            }
        }
    }
}
</script>

<style scoped>
body {
    font-size: 12px;
}
dt {
    width: 100px;
    text-align: right;
}
dl {
    clear: both;
    overflow: hidden;
}
dl.hl {
    background: #ddd;
}
dt,
dd {
    float: left;
    height: 40px;
    line-height: 40px;
    margin-left: 10px;
}
button {
    font-size: 14px;
    font-weight: bold;
    width: 100px;
    height: 30px;
    margin: 0 10px;
}

.disabled {
    color: #999;
    border: 1px dashed #666;
}
.active {
    color: red;
}

.top-but {
    margin: 10px;
}

#skuId {
    height: 24px;
    font-size: 14px;
    line-height: 24px;
}
</style>
